package io.mft.commons.util.xml;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/*import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;*/
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.hutool.core.util.ObjectUtil;
/**
 * xml加载处理器
 * @类型名称：XmlLoader
 * @说明：TODO
 * @创建者: 胡常建  
 * @创建时间: 2018年7月3日 下午2:24:06
 * @修改者: 胡常建  
 * @修改时间: 2018年7月3日 下午2:24:06
 */
public class XmlLoader {
	static Logger logger=LoggerFactory.getLogger(XmlLoader.class);
    public static final XmlLoader instance=new XmlLoader();
    public class NodeWrapper{
        private int index=0;
    	private String id;
    	private String xmlTag;
    	private boolean isEffectRoot=false;
    	public String getXmlTag() {
			return xmlTag;
		}
    	public void setXmlTag(String xmlTag) {
			this.xmlTag = xmlTag;
		}
    	public void setEffectRoot(boolean isEffectRoot) {
			this.isEffectRoot = isEffectRoot;
		}
    	public boolean isEffectRoot() {
			return isEffectRoot;
		}
    	public void setId(String id) {
			this.id = id;
		}
    	public String getId() {
			return id;
		}
        private Node node;
        private  String text;
        public String getText() {
            return text;
        }
        public String getNodeName() {
            return node.getName();
        }
        public String getAttributeValue(String attrName){
            return this.attrCache.get(attrName);
        }
        private HashMap<String, String> attrCache = new HashMap<String, String>();
        public NodeWrapper(String id,Node node){
        	this.id=id;
            this.node=node;
            initNodeAttrValue();
            initNodeTextValue();
        }
        private void initNodeTextValue() {
            Element element_node = (Element) node;
            String text = element_node.getTextTrim();
            this.text=text;
        }
        private void initNodeAttrValue() {
            Element element_node = (Element) node;
            int len= element_node.attributeCount();
            for (int i = 0; i < len; i++) {
                Attribute attr=element_node.attribute(i);
                String name=attr.getName();
                String value=attr.getValue();
                this.attrCache.put(name, value);
            }
        }
        public int getIndex()
        {
            return index;
        }
        public void setIndex(int index)
        {
            this.index = index;
        }
        public Node getNode() {
			return node;
		}
    }
    private ConcurrentHashMap<String, NodeWrapper> nodes = new ConcurrentHashMap<String, NodeWrapper>();
    private HashSet<String>  resourcePath=new HashSet<String>();
    private static boolean CACHESTATUS=true;

	/*
	 * private String analysisPathToPackageQuailiedName(String resourcePath){ String
	 * pathName = IOUtil.lineToDotSplitPath(resourcePath); URL
	 * t=XmlLoader.class.getClassLoader().getResource(".");//???????? String
	 * resource = IOUtil.lineToDotSplitPath(t.getPath()); pathName =
	 * pathName.substring(resource.length() + 1); return pathName; }
	 */
    public synchronized void clear(){
        nodes.clear();
    }
    public synchronized  void loadSystemDirXmlNodes(String xmlPath) {
    	InputStream inputStream=null;
        try {
        	File file=new File(xmlPath);
        	URL url=file.toURI().toURL();
			inputStream=url.openStream();
            if (CACHESTATUS) {
                if (this.resourcePath.contains(xmlPath)) {
                    return;
                }else {
                    this.resourcePath.add(xmlPath);
                }
            }
            SAXReader reader = new SAXReader();
            reader.setValidation(false);
            reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
            Document doc =  reader.read(inputStream);
            Element systemElement = doc.getRootElement();
            String idname = systemElement.attributeValue("id");
            String[] splits =url.getPath().split("/");
            String resourcePackageQuailifiedPath=splits[splits.length-1];
            if (!ObjectUtil.isEmpty(idname)) {
                idname = resourcePackageQuailifiedPath + "." + idname;
               
            }else {
                idname = resourcePackageQuailifiedPath;
            }

            analysisNodeToCache(systemElement, idname,resourcePackageQuailifiedPath,0);
		
        } catch (Exception e) {
           logger.error("", e);
        }finally{
        	if (inputStream!=null) {
        		try {
        			inputStream.close();
				} catch (Exception e2) {
					logger.error("", e2);
				}
			}
        }
    }
    public synchronized  void loadXmlText(String id,String xmlText) {
    	InputStream inputStream= new   ByteArrayInputStream(xmlText.getBytes());
        try {
            SAXReader reader = new SAXReader();
            reader.setValidation(false);
            reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
            Document doc =  reader.read(inputStream);
            Element systemElement = doc.getRootElement();
            String idname = systemElement.attributeValue("id");
            if (!ObjectUtil.isEmpty(idname)) {
                idname = id + "." + idname;
               
            }else {
                idname = id;
            }
            analysisNodeToCache(systemElement, idname,id,0);
        } catch (Exception e) {
           logger.error("", e);
        }finally{
        	if (inputStream!=null) {
        		try {
        			inputStream.close();
				} catch (Exception e2) {
					logger.error("", e2);
				}
			}
        }
        
    }
    public synchronized  void loadSystemDirNodes(String resourceFileName) {
    	InputStream inputStream=null;
        try {
    		URL url=this.getClass().getClassLoader().getResource(resourceFileName);
    		if (url==null) {
				url=XmlLoader.class.getClassLoader().getResource(".");
				String path=null;
				if (url==null) {
					path=System.getProperty("user.dir")+File.separator+"classes";
				}else {
					path=url.getPath();
				}
				path=path+File.separator+resourceFileName;
				File file=new File(path);
				url=file.toURI().toURL();
			}
			inputStream=url.openStream();
            if (CACHESTATUS) {
                if (this.resourcePath.contains(url.getPath())) {
                    return;
                }else {
                    this.resourcePath.add(url.getPath());
                }
            }
            SAXReader reader = new SAXReader();
            reader.setValidation(false);
            reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
            Document doc =  reader.read(inputStream);
            Element systemElement = doc.getRootElement();
            String idname = systemElement.attributeValue("id");
            String[] splits =url.getPath().split("\\"+File.separator);
            String resourcePackageQuailifiedPath=splits[splits.length-1];
            if (!ObjectUtil.isEmpty(idname)) {
                idname = resourcePackageQuailifiedPath + "." + idname;
               
            }else {
                idname = resourcePackageQuailifiedPath;
            }

            analysisNodeToCache(systemElement, idname,resourcePackageQuailifiedPath,0);
		
        } catch (Exception e) {
           logger.error("", e);
        }finally{
        	if (inputStream!=null) {
        		try {
        			inputStream.close();
				} catch (Exception e2) {
					logger.error("", e2);
				}
			}
        }
        
    }
    private  void analysisNodeToCache(Element element, String idLink,String resourcePackageQuailifiedPath,int index) {
        NodeWrapper nodeWrapper=new NodeWrapper(idLink,element);
        String t_id=idLink.substring(resourcePackageQuailifiedPath.length());
        String [] array=t_id.split("\\.");
        if (array.length==2) {
        	nodeWrapper.setEffectRoot(true);
		}
        nodeWrapper.setXmlTag(element.getName());
        nodeWrapper.setIndex(index);
        if (nodes.containsKey(idLink)) {
			throw new IllegalStateException("不允许文件包含相同ID节点:-->>>路径："+resourcePackageQuailifiedPath+";ID:"+idLink);
		}
       // logger.info("加载的XML-ID："+idLink);
        nodes.put(idLink, nodeWrapper);
        List<?> childElements=element.elements();
        for (Object object : childElements) {
			Element childElement=(Element)object;
            if (childElement.getNodeType()!=Node.ELEMENT_NODE) {
                continue;
            }
            String id = childElement.attributeValue("id");
            if (ObjectUtil.isEmpty(id)) {
				id=childElement.getName();
				String name=childElement.attributeValue("name");
				if (!ObjectUtil.isEmpty(name)) {
					id += "."+name;
				}
			}
            StringBuffer idBuffer = new StringBuffer(idLink).append(".").append(id);
            index++;
            analysisNodeToCache(childElement, idBuffer.toString(),resourcePackageQuailifiedPath,index);
		}
    }
public synchronized NodeWrapper getNodeWrapper(String filePackageQuailiedName,String nodeId) {
	StringBuilder builder=new  StringBuilder(filePackageQuailiedName);
	builder.append(".");
	builder.append(nodeId);
	String id=builder.toString().trim();
    NodeWrapper nodeWrapper= nodes.get(id);
    return nodeWrapper;
}
public synchronized NodeWrapper getNodeWrapper(String nodeId) {
    NodeWrapper nodeWrapper= nodes.get(nodeId);
    return nodeWrapper;
}
public synchronized List<NodeWrapper> getAllNodeWrapper(String resourcePath) {
   // String path=analysisPathToPackageQuailiedName(resourcePath);
    String[] splits =resourcePath.split("\\"+File.separator);
    String path=splits[splits.length-1];
    List< NodeWrapper> list=new ArrayList< NodeWrapper>();
    Iterator<String> iterator= nodes.keySet().iterator();
    while (iterator.hasNext()) {
        String key = (String) iterator.next();
        if (key.indexOf(path)!=-1) {
            list.add(nodes.get(key));
        }
    }
    return list;
}
public synchronized List<NodeWrapper> getAllNodeWrapperByFileName(String resourceFileName) {
    String path=resourceFileName;
    List< NodeWrapper> list=new ArrayList< NodeWrapper>();
    Iterator<String> iterator= nodes.keySet().iterator();
    while (iterator.hasNext()) {
        String key = (String) iterator.next();
        if (key.indexOf(path)!=-1) {
            list.add(nodes.get(key));
        }
    }
    return list;
}
    public synchronized String getXmlNodeContent(String filePackageQuailiedName,
            String nodeId) {
        NodeWrapper nodeWrapper = getNodeWrapper(nodeId);
        if (nodeWrapper==null) {
            return "";
        }
        String text= nodeWrapper.getText();
        return text;
    }
}
